package com.shhic.hhplt.server.biz;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import com.shhic.hhplt.server.exceptions.CodeExhaustException;
import com.shhic.hhplt.server.exceptions.NoSerialCodeException;
import com.shhic.hhplt.server.service.ICodePersistService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.shhic.hhplt.server.model.SerialCode;

@Component
public class SerialCodeMaintaince implements ISerialCodeMaintaince {
    @Autowired
    ICodePersistService cpService;

    private Map<String, ISerialCodeGeneraterContainer> scContainerMap = new HashMap<String, ISerialCodeGeneraterContainer>();

    @PostConstruct
    public void loadAllSerialCode() {
        List<SerialCode> allSerialCode = cpService.getAllSerialCode();
        synchronized (scContainerMap) {
            for (SerialCode s : allSerialCode) {
                if (s.isAvailable()) {
                    scContainerMap.put(s.getCodeNameTitle(), new SerialCodeGeneraterContainer(s));
                }
            }
        }
    }

    @Override
    public String generateSerialCode(String key) throws CodeExhaustException, NoSerialCodeException {
        ISerialCodeGeneraterContainer serialCodeGeneraterContainer;
        synchronized (scContainerMap) {
            if (!scContainerMap.containsKey(key)) throw new NoSerialCodeException();
            serialCodeGeneraterContainer = scContainerMap.get(key);
        }
        String serialCode = serialCodeGeneraterContainer.getAndGenerateCode();

        if (!cpService.removeIfExistRetrievedCode(key, serialCode)) {
            //如果是回收码，是不能持久成当前码的。目前逻辑不会乱，但如果这里恰好重启 服务，当前码就丢了。
            cpService.updateNowSerialCode(scContainerMap.get(key).getCodeName(), serialCode);
        }
        return serialCode;
    }

    @Override
    public void notifyDeletion(String codeName) {
        synchronized (scContainerMap) {
            SerialCode sc = new SerialCode();
            sc.setCodeName(codeName);
            String codeNameTitle = sc.getCodeNameTitle();
            if (scContainerMap.containsKey(codeNameTitle) &&
                    scContainerMap.get(codeNameTitle).getCodeName().equals(codeName)) {
                scContainerMap.remove(codeNameTitle);
            }
        }
    }

    @Override
    public void updateSerialCode(SerialCode sc) {
        synchronized (scContainerMap) {
            scContainerMap.remove(sc.getCodeNameTitle());
            if (sc.isAvailable()) {
                scContainerMap.put(sc.getCodeNameTitle(), new SerialCodeGeneraterContainer(sc));
            }
        }
    }

    @Override
    public void retrieveSerialCode(String codeName, String code) throws NoSerialCodeException {
        ISerialCodeGeneraterContainer serialCodeGeneraterContainer;
        synchronized (scContainerMap) {
            if (!scContainerMap.containsKey(codeName)) throw new NoSerialCodeException();
            serialCodeGeneraterContainer = scContainerMap.get(codeName);
            serialCodeGeneraterContainer.retrieveCode(code);
        }
        cpService.addRetrivedCode(codeName, code);
    }
}
